package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.enums.BActivityClassEnum;
import cn.huiyunche.base.service.enums.BActivityTypeEnum;
import cn.huiyunche.base.service.enums.BFeeTypeEnum;
import cn.huiyunche.base.service.form.VehiClesInfoFrom;
import cn.huiyunche.base.service.interfaces.*;
import cn.huiyunche.base.service.model.BActivity;
import cn.huiyunche.base.service.model.BFeeDiscount;
import cn.huiyunche.base.service.model.BStowageModel;
import cn.huiyunche.base.service.vo.BActivityVo;
import cn.huiyunche.base.service.vo.BProductCoefficientVo;
import cn.huiyunche.base.service.vo.SOrderFeeDetailVo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FeesServiceImpl implements FeesService {

    private static final Logger LOGGER = LoggerFactory.getLogger(FeesServiceImpl.class);

    @Autowired
    private SShippingFeeService sShippingFeeService;

    @Autowired
    private SExtractFeeService sExtractFeeService;

    @Autowired
    private SDeliveryFeeService sDeliveryFeeService;

    @Autowired
    private SInsuranceFeeService sInsuranceFeeService;

    @Autowired
    private BProductsService productsService;

    @Autowired
    private BFeeDiscountService bFeeDiscountService;

    @Autowired
    private BPositionSubsidyService bPositionSubsidyService;

    @Autowired
    private BActivityService bActivityService;

    @Autowired
    private SInvoiceRateService sInvoiceRateService;

    @Autowired
    private SKmFeeService sKmFeeService;

    @Autowired
    private STrailerFeeService sTrailerFeeService;

    @Autowired
    private SBaseFeeService sBaseFeeService;

    @Override
    public Map<String, Object> queryFees(String depaCode, String destCode, BigDecimal distance, BStowageModel stowageModel, Long productId, Date startDate, Integer AMorPM, List<VehiClesInfoFrom> vehicles,
                                         BigDecimal estValue, Boolean hasInsurance, Boolean isPick, Boolean isDeliv, Boolean hasInvoice, Boolean isSave) {
        LOGGER.info("queryFees params : {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}", depaCode, destCode, distance, productId, startDate, AMorPM, vehicles.size(), estValue, hasInsurance, isPick, isDeliv, hasInvoice, isSave);
        if (StringUtils.isBlank(depaCode)) {
            LOGGER.error("queryFees depaCode must not be null");
            throw new IllegalArgumentException("起运地编码不能为空！");
        }
        if (StringUtils.isBlank(destCode)) {
            LOGGER.error("queryFees destCode must not be null");
            throw new IllegalArgumentException("目的地编码不能为空！");
        }
        if (null == distance) {
            LOGGER.error("queryFees distance must not be null");
            throw new IllegalArgumentException("运距不能为空！");
        }
        if (CollectionUtils.isEmpty(vehicles)) {
            LOGGER.error("queryFees vehicles must not empty");
            throw new IllegalArgumentException("车辆信息不能为空！");
        }
        if (null == estValue) {
            LOGGER.error("queryFees estValue must not be null");
            throw new IllegalArgumentException("车型估值不能为空！");
        }
        if (null == isPick) {
            LOGGER.info("queryFees isPick is null");
            isPick = false;
        }
        if (null == isDeliv) {
            LOGGER.info("queryFees isDeliv is null");
            isDeliv = false;
        }
        if (null == hasInvoice) {
            LOGGER.info("queryFees hasInvoice is null");
            isDeliv = true;
        }
        if (null == isSave) {
            LOGGER.info("queryFees isSave is null");
            isSave = false;
        }

        Map<String, Object> map = new HashMap<>();
        List<SOrderFeeDetailVo> list = new ArrayList<>();

        //获取符合运距的物流产品信息
        BProductCoefficientVo coe = productsService.getCoefficients(distance, null, startDate, AMorPM).get(0);
        BigDecimal coefficient = BigDecimal.valueOf(1);
        if (null != coe) {
            coefficient = coe.getCoefficient();
            map.put("productId", coe.getProductId());
            //到达时间
            map.put("arrivalDate", coe.getEndTime());
        }

        //计算线路补贴（始发地和目的之间综合级别系数补贴）
        BigDecimal lineSubsidy = bPositionSubsidyService.computeSubsidy(depaCode, destCode);

        //计算基础运价（阶梯型）
        BigDecimal baseFee = sShippingFeeService.queryBaseShippingFee(distance, sShippingFeeService.getList(distance));

        //计算全部车辆总运费
        SOrderFeeDetailVo shippingFee = sShippingFeeService.queryVehiclesShippingFee(coefficient, baseFee.add(lineSubsidy), vehicles, stowageModel);
        list.add(shippingFee);

        //车辆总数
        int sum = vehicles.stream().mapToInt(v -> v.getAmount()).sum();

        //计算提车费
        SOrderFeeDetailVo extractcost = sExtractFeeService.queryExtractFee(isPick, sum);
        list.add(extractcost);

        //计算交车费
        SOrderFeeDetailVo returncost = sDeliveryFeeService.queryDeliveryFee(isDeliv, sum);
        list.add(returncost);

        //计算保险费
        SOrderFeeDetailVo insurance = sInsuranceFeeService.queryInsuranceFee(estValue, vehicles.stream().mapToInt(ve -> ve.getAmount()).sum(), hasInsurance);
        list.add(insurance);

        this.buildDiscountFees(map, list);

        //折扣前总费用
        BigDecimal actualtotalBefore = BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getCost().longValue()).sum()).setScale(2);
        //计算折扣前发票费
        SOrderFeeDetailVo invoiceFeeBefore = sInvoiceRateService.computeInvoiceFee(hasInvoice, null, actualtotalBefore);
        map.put("invoiceFeeBefore", invoiceFeeBefore);
        if (hasInvoice) {
            SOrderFeeDetailVo detail = list.stream().filter(vo -> vo.getFeeCode() == BFeeTypeEnum.SHIPPING.getValue()).collect(Collectors.toList()).get(0);
            detail.setCost(detail.getCost().add(invoiceFeeBefore.getCost()));
        }

        //折扣后总费用
        BigDecimal actualtotalAfter = BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getActualAmount().longValue()).sum()).setScale(2);
        //计算折扣后发票费
        SOrderFeeDetailVo invoiceFeeAfter = sInvoiceRateService.computeInvoiceFee(hasInvoice, null, actualtotalAfter);
        map.put("invoiceFeeAfter", invoiceFeeAfter);
        if (hasInvoice) {
            SOrderFeeDetailVo detail = list.stream().filter(vo -> vo.getFeeCode() == BFeeTypeEnum.SHIPPING.getValue()).collect(Collectors.toList()).get(0);
            detail.setActualAmount(detail.getActualAmount().add(invoiceFeeAfter.getActualAmount()));
        }

        map.put("total", BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getCost().longValue()).sum()).setScale(2));
        map.put("actualtotal", BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getActualAmount().longValue()).sum()).setScale(2));
        map.put("fees", list);

        //true 返回发票税费费用详情做保存用
        if (isSave) {
            invoiceFeeAfter.setCost(invoiceFeeBefore.getActualAmount());
            list.add(invoiceFeeAfter);
        }

        return map;
    }

    private void buildDiscountFees(Map<String, Object> map, List<SOrderFeeDetailVo> list) {
        //活动折扣
        final BActivity activity = bActivityService.getByTypeAndClass(0, BActivityTypeEnum.FEE_DISCOUNT.getValue(), BActivityClassEnum.DISCOUNT.getValue());
        if (null != activity) {
            //活动信息
            BActivityVo vo = new BActivityVo();
            vo.setDesc(activity.getDescription());
            vo.setDiscount(true);
            map.put("activity", vo);

            //获取费用类型的折扣
            List<Long> feeIds = list.stream().map(fee -> fee.getId()).collect(Collectors.toList());
            List<BFeeDiscount> discounts = bFeeDiscountService.getList(feeIds);

            if (CollectionUtils.isNotEmpty(discounts)) {
                list.forEach(fee -> {
                    List<BFeeDiscount> sList = discounts.stream().filter(discount ->
                            discount.getFeeTypeId() == fee.getId()).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(sList)) {
                        fee.setIsDiscount(true);
                        fee.setActualAmount(sList.get(0).getDiscount().multiply(fee.getCost()).setScale(0, RoundingMode.UP).setScale(2));
                    } else {
                        fee.setActualAmount(fee.getCost());
                    }
                });
            }
        } else {
            BActivityVo vo = new BActivityVo();
            vo.setDesc(null);
            vo.setDiscount(false);
            map.put("activity", vo);

            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(fee -> fee.setActualAmount(fee.getCost()));
            }
        }
    }

    @Override
    public Map<String, Object> queryIntracityFees(String areaCode, BigDecimal distance, Integer vehicleNum, Integer trailerId) {
        LOGGER.info("queryIntracityFees params : {}", trailerId, distance, vehicleNum);
        if (null == trailerId) {
            LOGGER.error("queryIntracityFees param trailerId must not be null");
            throw new IllegalArgumentException("拖车类型主键不能为空");
        }
        if (null == distance) {
            LOGGER.error("queryIntracityFees distance must not be null");
            throw new IllegalArgumentException("里程不能为空");
        }
        if (null == vehicleNum) {
            LOGGER.error("queryIntracityFees vehicleNum must not be null");
            throw new IllegalArgumentException("车辆数不能为空");
        }

        //返回map数据
        Map<String, Object> map = new HashMap<>();

        //费用数组
        List<SOrderFeeDetailVo> list = new ArrayList<>();

        //计算起步费
        SOrderFeeDetailVo startingFee = sBaseFeeService.queryBaseFee(areaCode);
        list.add(startingFee);

        //计算里程费
        SOrderFeeDetailVo kmFee = sKmFeeService.queryKmFee(areaCode, distance);
        list.add(kmFee);

        //计算保险费
        SOrderFeeDetailVo insuranceFee = sInsuranceFeeService.queryIncracityInsuranceFee();
        list.add(insuranceFee);

        //计算特型车加价费
        SOrderFeeDetailVo trailerFee = sTrailerFeeService.queryTrailerFee(areaCode, trailerId);
        list.add(trailerFee);

        list.forEach(fee -> {
            fee.setCost(fee.getCost().multiply(BigDecimal.valueOf(vehicleNum)));
            fee.setActualAmount(fee.getActualAmount().multiply(BigDecimal.valueOf(vehicleNum)));
        });

        this.buildDiscountFees(map, list);

        map.put("total", BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getCost().longValue()).sum()).setScale(2));
        map.put("actualTotal", BigDecimal.valueOf(list.stream().mapToLong(vo -> vo.getActualAmount().longValue()).sum()).setScale(2));
        map.put("fees", list);

        return map;
    }

}
